# coding: utf-8

# -------------------------------------------------------------------------------
# Name:         validator.py
# Description:
# Author:       XiangjunZhao
# EMAIL:        2419352654@qq.com
# Date:         2019/11/18 17:32
# -------------------------------------------------------------------------------
import json
import logging

from apps.HttpAutoTestService.core.builtin.comparator_dict import comparator_dict
from apps.HttpAutoTestService.core.extractor import Extractor
from apps.HttpAutoTestService.core.loader import load_built_in_comparators

logger = logging.getLogger(__name__)


class Validator(object):
    """
    校验器
    主要功能：
        1、格式化校验变量
        2、校验期望结果与实际结果与预期一致，并返回校验结果
    """

    # 取舍来源映射字典
    source_dict = {
        'url': '请求URL',
        'headers': '请求响应头',
        'status_code': '响应状态码',
        'results': '请求响应内容',
        'elapsed': '请求响应时长'
    }
    # 取舍来源映射字典
    extractor_dict = {
        'JSONPATH': 'JsonPath表达式',
        'REGEXP': '正则表达式'
    }

    @classmethod
    def validate(cls, resp_obj=None, variable_list=None):
        """
        校验期望结果与实际结果与预期一致
        Args:
            resp_obj: ResponseObject对象实例
            variable_list:

        Returns:

        """

        if variable_list is None:
            variable_list = []
        validate_pass = "PASS"
        built_in_comparators = load_built_in_comparators()

        # 记录校验失败的原因
        failure_reason = []
        for variable in variable_list:
            # 取值来源
            source = variable.get('source', 'results')
            # 取值方式
            extractor = variable.get('extractor', 'JSONPATH')
            # 取值表达式
            expression = variable.get('expression')
            # 期望值
            expect_value = variable.get('expect_value')
            # 断言方法
            comparator = variable.get('comparator')

            extract_result = Extractor.extract_value(resp_obj=resp_obj, variable_list=[
                {'source': source, 'variable_name': 'actual_value', 'extractor': extractor, 'expression': expression}])
            actual_value = extract_result['actual_value']
            if not isinstance(actual_value, str):
                actual_value = json.dumps(actual_value, ensure_ascii=False)
            try:
                # 获取比较器
                fun = built_in_comparators[comparator]
                fun(actual_value=actual_value, expect_value=expect_value)
            except (AssertionError, TypeError):
                validate_pass = "FAIL"
                failure_reason.append({
                    '检查项取值来源': cls.source_dict.get(source),
                    '检查项取值方式': cls.extractor_dict.get(extractor),
                    '检查项取值表达式': expression,
                    '期望值': expect_value,
                    '实际值': actual_value,
                    '断言方法': comparator_dict.get(comparator),
                })
        return validate_pass, failure_reason
